package sensitive

import (
	"fmt"
	"regexp"

	"sync"
	"time"

	. "go-share/models"
	msensitive "go-share/models/sensitive"

	"go-share/logging"
	"go-share/store/redis"
)

// 获取敏感词列表
func GetSensitiveWordList() ([]string, error) {

	// 读缓存
	key := REDIS_SENSITIVE_WORD
	wordList, err := redis.Smembers(key)
	if err == nil && len(wordList) > 0 {
		return wordList, nil
	}
	redis.Del(key)

	// 读数据库
	s := msensitive.NewSensitiveWord()
	contentList, err := s.GetContentList()
	if err != nil {
		logging.Debug("Get Sensitive Content List | %v", err)
		return contentList, err
	}

	// 写缓存
	for _, v := range contentList {
		redis.Sadd(key, v)
	}

	return contentList, nil
}

// 获取正则表达式
func GetRegExp() (string, error) {
	sensitiveWordList, err := GetSensitiveWordList()
	if err != nil {
		logging.Debug("Get Sensitive Word List | %v", err)
		return "", err
	}

	// 正则表达式
	var regExpr string
	for i, v := range sensitiveWordList {
		if i == 0 {
			regExpr += fmt.Sprintf("(%v|", v)
		} else if i == len(sensitiveWordList)-1 {
			regExpr += fmt.Sprintf("%v)", v)
		} else {
			regExpr += fmt.Sprintf("%v|", v)
		}
	}

	return regExpr, nil
}

func GetRegExpFromCache() (string, error) {

	// 读缓存
	key := REDIS_SENSITIVE_WORD_REG
	wordReg, err := redis.Get(key)
	if err == nil && len(wordReg) > 0 {
		return wordReg, nil
	}
	redis.Del(key)

	// 读数据库
	s := msensitive.NewSensitiveWord()
	contentList, err := s.GetContentList()
	if err != nil {
		logging.Debug("Get Sensitive Content List | %v", err)
		return "", err
	}
	reg, err := regexp.Compile(`(\*|\.|\?|\+|\$|\^|\[|\]|\(|\)|\{|\}|\||\\|\/)`)
	if err != nil {
		logging.Debug("Regxp Compile | %v", err)
		return "", nil
	}
	for i := len(contentList) - 1; i >= 0; i-- {
		ok := reg.MatchString(contentList[i])
		if ok {
			contentList = append(contentList[:i], contentList[i+1:]...)
		}
	}

	// 正则表达式
	var regExpr string
	for i, v := range contentList {
		if i == 0 {
			regExpr += fmt.Sprintf("(%v|", v)
		} else if i == len(contentList)-1 {
			regExpr += fmt.Sprintf("%v)", v)
		} else {
			regExpr += fmt.Sprintf("%v|", v)
		}
	}

	// 写缓存
	redis.Set(key, []byte(regExpr))

	return regExpr, nil
}

// 过滤敏感词
func Filter(content string) (string, error) {
	return content, nil

	regExp, err := GetRegExpFromCache()
	if err != nil {
		logging.Debug("Get RegExp | %v", err)
		return "", err
	}

	reg, err := regexp.Compile(regExp)
	if err != nil {
		logging.Debug("Regexp Compile | %v", err)
		return "", err
	}

	data := reg.ReplaceAllString(content, "")

	return data, nil
}

//**********************wdk 20170711 add -begin
var (
	SensWords map[rune]interface{}
	cLock     sync.RWMutex
)

const (
	SENSWORDS_LENGTH     = 1024
	SUB_SENSWORDS_LENGTH = 16
	CHECK_VERSION_TIMER  = 60 * 10 // 60 * time.Second
)

func InitSensitive() {
	SensWords = make(map[rune]interface{}, SENSWORDS_LENGTH)

	getDatabaseWord(SensWords)
	go timerCheckVersion()
}

//getDatabaseWord ...
func getDatabaseWord(m map[rune]interface{}) (bool, error) {
	// 读数据库
	s := msensitive.NewSensitiveWord()
	contentList, err := s.GetContentList()
	if err != nil {
		logging.Debug("Get Sensitive Content List | %v", err)
		return false, err
	}

	/*	reg, err := regexp.Compile(`(\*|\.|\?|\+|\$|\^|\[|\]|\(|\)|\{|\}|\||\\|\/)`)
		if err != nil {
			logging.Debug("Regxp Compile | %v", err)
			return false, err
		}
		for i := len(contentList) - 1; i >= 0; i-- {
			ok := reg.MatchString(contentList[i])
			if ok {
				contentList = append(contentList[:i], contentList[i+1:]...)
			}
		}*/

	for _, v := range contentList {
		initWordsMap(m, v)
		//logging.Debug("IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII:%v;%v;%v;", v, len(v), len("哈哈哈"))
	}
	return true, nil
}

//timerCheckVersion 定时检测是否mysql有更新
func timerCheckVersion() {
	key := REDIS_SENSITIVE_WORD_MSG_VERSION
	lastVersion, _ := redis.Get(key)
	for {
		logging.Debug("sensitive word TimerCheckVersion begin!")
		time.Sleep(CHECK_VERSION_TIMER * time.Second)
		ver, err := redis.Get(key)
		if err != nil || len(ver) == 0 {
			continue
		}
		if ver != lastVersion {
			newSensWords := make(map[rune]interface{}, SENSWORDS_LENGTH)
			if b, err := getDatabaseWord(newSensWords); b && err == nil {
				cLock.Lock()
				SensWords = newSensWords
				cLock.Unlock()
				logging.Debug("sensitive word Map update complete!")
			}
			lastVersion = ver
		}
	}
}

//initWordsMap 添加敏感字到map中
func initWordsMap(m map[rune]interface{}, str string) {
	//m := SensWords
	for _, word := range str {
		m, _ = addRuneToMap(m, word)
	}
	m['`'] = nil //结束标记
}

//addRuneToMap
func addRuneToMap(m map[rune]interface{}, ru rune) (map[rune]interface{}, bool) {
	if v, ok := m[ru]; ok {
		return v.(map[rune]interface{}), true
	} else {
		m[ru] = make(map[rune]interface{}, SUB_SENSWORDS_LENGTH)
		return m[ru].(map[rune]interface{}), true
	}
}

//FilterString 过滤字符串匹配后敏感字符变成*
func FilterString(str string) (string, error) {
	cLock.RLock()
	m := SensWords
	b := false
	count := 0
	index := 0
	bb := []rune(str)
	for _, word := range str {
		//logging.Debug("00FFFFFFFFF%c;map:%v; len(map):%v;\n", word, m, len(m))
		if m, b = findWord(word, m); b == false {
			//m = SensWords
			if m, b = findWord(word, SensWords); b == false {
				m = SensWords
				count = 0
			} else {
				count = 1
				if _, ok := m['`']; ok {
					for i := 0; i < count; i++ { //替换成*
						bb[index+1-count+i] = '*'
					}
					logging.Debug("FilterString() Find index:%v; count:%v; string:%v!\n", index, count, string(bb))
					count = 0
				}
			}
		} else {
			count++
			//logging.Debug("FFFFFFFFFind index:%v; count:%v; string:%v; word:%c!\n", index, count, string(bb), word)
			//if len(m) == 1
			if _, ok := m['`']; ok {
				for i := 0; i < count; i++ { //替换成*
					bb[index+1-count+i] = '*'
				}
				logging.Debug("FilterString() Find index:%v; count:%v; string:%v; word:%c!\n", index, count, string(bb), word)
				count = 0
			}
		}
		index++
	}
	cLock.RUnlock()
	return string(bb), nil
}

//FilterStringRet 过滤字符串匹配后敏感字符直接返回
func FilterStringRet(str string) bool {
	cLock.RLock()
	m := SensWords
	b := false
	bb := []rune(str)
	ret := false
	for _, word := range str {
		if m, b = findWord(word, m); b == false {
			if m, b = findWord(word, SensWords); b == false {
				m = SensWords
			} else {
				if _, ok := m['`']; ok {
					logging.Debug("FilterString() Find string:%v!\n", string(bb))
					ret = true
					break
				}
			}
		} else {
			//logging.Debug("FFFFFFFFFind index:%v; count:%v; string:%v; word:%c!\n", index, count, string(bb), word)
			//if len(m) == 1
			if _, ok := m['`']; ok {
				logging.Debug("FilterString() Find string:%v; word:%c!\n", string(bb), word)
				ret = true
				break
			}
		}
	}
	cLock.RUnlock()
	return ret
}

//findWord ...
func findWord(ru rune, m map[rune]interface{}) (map[rune]interface{}, bool) {
	if v, ok := m[ru]; ok {
		return v.(map[rune]interface{}), true
	} else {
		return nil, false
	}
}

//**********************wdk 20170711 add -end
